package org.byd.dmsja;

import org.byd.dmsja.utils.Method;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

public class ZjzNodeUtil {
    public static <T> ZjzNode<T> zjzBuildNode(CNodeBuildOption<T> option) {
        Method.IFunc1<T, Object> fnGetId = (T record) -> {
            return option.zjzIdSelector.apply(record);
        };

        Method.IFunc1<T, Object> fnGetParentId = (T record) -> {
            return option.zjzParentIdSelector.apply(record);
        };

        Method.IPredicate1<T> fnHasParent = (T xRecord) -> {
            return option.zjzDataList.stream().anyMatch(x -> fnGetId.apply(x) == fnGetParentId.apply(xRecord));
        };

        Method.IFunc0<List<T>> fnGetTopList = () -> {
            return option.zjzDataList.stream().filter(x -> !fnHasParent.apply(x)).collect(Collectors.toList());
        };

        Method.IFunc1<T, List<T>> fnGetChildList = (T xRecord) -> {
            return option.zjzDataList.stream().filter(x -> Objects.equals(fnGetParentId.apply(x),
                    fnGetId.apply(xRecord))).collect(Collectors.toList());
        };

        ZjzNode<T> node = new ZjzNode<>();
        AtomicReference<Method.IAction1<ZjzNode<T>>> acCallback = new AtomicReference<>();
        acCallback.set((ZjzNode<T> xCurrentNode) -> {
            List<T> tmpList = xCurrentNode.zjzRecord == null ? fnGetTopList.apply() :
                    fnGetChildList.apply(xCurrentNode.zjzRecord);
            tmpList.forEach(x -> {
                ZjzNode<T> xNode = new ZjzNode<>();
                xNode.zjzRecord = x;
                xNode.zjzParentNode = xCurrentNode;
                xNode.zjzChildNodeList = new ArrayList<>();
                xCurrentNode.zjzChildNodeList.add(xNode);
                acCallback.get().accept(xNode);
            });
        });
        acCallback.get().accept(node);
        return node;
    }

    public static class CNodeBuildOption<T> {
        public List<T> zjzDataList = new ArrayList<>();
        public Method.IFunc1<T, Object> zjzIdSelector;
        public Method.IFunc1<T, Object> zjzParentIdSelector;
    }
}
